package monitor

import (
	"gitee.com/igolang/imoney/internal/app/system/entities"
	"gitee.com/igolang/imoney/internal/app/system/entities/constants"
	"gitee.com/igolang/imoney/internal/app/system/keys"
	"gitee.com/igolang/imoney/internal/core/client"
	"gitee.com/igolang/imoney/internal/models/dao"
	"gitee.com/igolang/imoney/internal/models/model"
	"gitee.com/igolang/pkg/xcfg"
	"gitee.com/igolang/pkg/xtime"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"gorm.io/gen"
	"strings"
	"time"
)

var Online = &online{}

type online struct{}

func (s *online) List(ctx *gin.Context) ([]map[string]string, error) {
	var req entities.UserOnlinePageListReq
	if err := ctx.ShouldBind(&req); err != nil {
		return nil, err
	}
	expired := xcfg.GetDuration("system.token.expired")
	if expired.Seconds() == 0 {
		expired = constants.TokenExpired
	}
	t := time.Now().Add(-expired)
	conds := []gen.Condition{
		dao.SysUser.LoginDate.Gt(xtime.Time(t)),
	}
	if req.UserName != "" {
		conds = append(conds, dao.SysUser.UserName.Like("%"+req.UserName+"%"))
	}
	type row struct {
		*model.SysUser
		DeptName string `json:"deptName"`
	}
	var userRows []*row
	err := dao.SysUser.Select(dao.SysUser.UserID, dao.SysUser.UserName, dao.SysDept.DeptName).
		LeftJoin(dao.SysDept, dao.SysDept.DeptID.EqCol(dao.SysUser.DeptID)).
		Where(conds...).Scan(&userRows)
	if err != nil {
		return nil, err
	}

	userMap := make(map[int64]*row)
	for _, v := range userRows {
		userMap[v.UserID] = v
	}

	rc := client.Redis()
	prefix := rc.KeyPrefix() + keys.UserToken("").Key
	pattern := prefix + "*"
	rows := make([]map[string]string, 0)
	var curr uint64
	for {
		var ks []string
		ks, curr = rc.Scan(ctx, curr, pattern, 10).Val()
		for _, k := range ks {
			if val := rc.HGetAll(ctx, k).Val(); len(val) > 0 {
				uid := cast.ToInt64(val["uid"])
				row, ok := userMap[uid]
				if !ok {
					continue
				}
				val["userName"] = row.UserName
				val["deptName"] = row.DeptName
				val["tokenId"] = strings.ReplaceAll(k, prefix, "")
				rows = append(rows, val)
			}
		}
		if curr == 0 {
			break
		}
	}
	return rows, nil
}
